package structure;



import java.util.ArrayList;
import java.util.Iterator;



public class cell {
	
	
	private ArrayList<ICellEventListener> _listeners = new ArrayList<ICellEventListener>();
	
	public synchronized void subscribe(ICellEventListener listener) { _listeners.add(listener); }
	public synchronized void unsubscribe(ICellEventListener listener) {	_listeners.remove(listener); }

	private synchronized void fireEventCellChanged() {
		Iterator<ICellEventListener> i = _listeners.iterator();
		while (i.hasNext()) {
			((ICellEventListener) i.next()).handleEventCellChanged(this);
		}
	}
	
	private int _mask = 511;
    private int _row;
    private int _col;
    private grid _grid;
	
    //default constructor
    public cell(grid g, int r, int c, int v) {
    	_row = r;
    	_col = c;
    	_grid = g;
    	setValueQuietly(v, true);
    }
    
    private void setValueQuietly(int v, boolean quiet) {
    	v = (1 <= v && v <= 9) ? v : 0;
    	int m = (v == 0) ? 511 : (int)Math.pow(2, v-1);
    	if (m != _mask) {
    		_mask = m;
    		if (!quiet) { fireEventCellChanged(); }
    	}
    }
    
    public void setValue(int v) { setValueQuietly(v, false); }
    
    private void setMaskQuietly(int m, boolean quiet) {
    	m = (1 <= m && m <= 511) ? m : 511;
    	if (m != _mask) {
    		_mask = m;
    		if (!quiet) { fireEventCellChanged(); }
    	}
    }
    public void setMask(int m) { setMaskQuietly(m, false); }
    
    public void setValueFixed(int v) {
    	setValueQuietly(v, true);
    }
    
    public void setMaskFixed(int m) {
    	setMaskQuietly(m, true);
    }
    
    
    public int getRowID() { return _row; }
    public int getColID() { return _col; }
    
    public int getMask() { return _mask; }
    
    public int getValue() { 
		double x = Math.log(_mask) / Math.log(2);
		return (x == Math.round(x)) ? (int)x + 1 : 0;
    }
    
    public void reset() { setMask(511); }
    
    public void togglePossible(int i) {
    	setMask(_mask ^ (int)Math.pow(2, i-1));
    }
    
    public void addPossible(int i) { 
    		setMask(_mask | (int)Math.pow(2, i-1));
    }
    
    public void removePossible(int i) { setMask(_mask & ~(int)Math.pow(2, i-1)); }
    public void removePossibleMask(int m) { setMask(_mask & ~m); }
    public boolean isPossible(int i) {
        return ((_mask & (int)Math.pow(2, i-1)) == (int)Math.pow(2, i-1) );
    }
    public boolean isPossibleMask(int m) { return ((_mask & m) == m); }
    public int cardinality() { return Integer.bitCount(_mask); }
    
    public String toString() {
        String t = "";
        for (int i = 1; i < 10; i++) { t += (isPossible(i)) ? i : "."; }
        return t;
    }
    
    public String toStringCoords() { return "R" + _row + "C" + _col; }
    
    public String toStringDetails() { return this.toStringCoords() + 
    	" : " + this.toString() + 
		" mask(" + this.getMask() + ")" +
		" value(" + this.getValue() + ")" +
		" cardinality(" + this.cardinality() + ")";
    }
    
}
